package com.example.config.intercept;

import cn.hutool.core.date.StopWatch;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.example.dto.SearchParamDTO;
import com.example.util.ExceptionUtil;
import com.example.util.LogUtil;
import com.example.util.SqlThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.LanguageDriverRegistry;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;

import java.lang.reflect.Field;

import static com.example.config.constant.ConstantConfig.*;

@Slf4j
public class DynamicSqlInterceptor implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        if (SqlCommandType.SELECT.equals(ms.getSqlCommandType()) && MAPPED_STATEMENT_ID.equals(ms.getId())) {
            log.info(LogUtil.getCurrentMethodPath() + "开始执行sql处理");
/*            StopWatch stopWatch = new StopWatch();
            stopWatch.start();*/
            String currentSqlContent = SqlThreadLocalUtil.getCurrentSqlContent();
            String script = SCRIPT_PREFIX + currentSqlContent + SCRIPT_SUFFIX;
            SqlSessionFactory sqlSessionFactory = SpringUtil.getBean(SQL_SESSION_FACTORY_BEAN_NAME, SqlSessionFactory.class);
            Configuration configuration = sqlSessionFactory.getConfiguration();
            LanguageDriverRegistry languageRegistry = configuration.getLanguageRegistry();

            SqlSource sqlSource = languageRegistry.getDriver(XMLLanguageDriver.class).createSqlSource(configuration, script, SearchParamDTO.class);
            BoundSql newBoundSql = new BoundSql(configuration, sqlSource.getBoundSql(parameter).getSql(), sqlSource.getBoundSql(parameter).getParameterMappings(), parameter);

            try {
                Field sqlField = boundSql.getClass().getDeclaredField(SQL_FILED_NAME);
                Field parameterMappingField = boundSql.getClass().getDeclaredField(PARAMETER_MAPPINGS);
                sqlField.setAccessible(true);
                parameterMappingField.setAccessible(true);
                sqlField.set(boundSql, newBoundSql.getSql());
                parameterMappingField.set(boundSql, newBoundSql.getParameterMappings());
            } catch (Exception e) {
                log.info(LogUtil.getCurrentMethodPath() + "SQL处理出现异常#异常信息", JSONUtil.toJsonStr(ExceptionUtil.getStackTrace(e)));
                throw new RuntimeException("服务异常");
            }
            log.info(LogUtil.getCurrentMethodPath() + "sql处理完成");
            /*stopWatch.stop();
            System.out.println("耗时：" + stopWatch.getLastTaskTimeMillis());*/
        }
    }

}
